package wt.jly.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * shiro的配置类
 *
 * @author lanyangji
 * @date 2018/9/18 14:19
 */
@Configuration
public class ShiroConfig {

    /**
     * 1. 创建 shiroFilterFactoryBean
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();

        // 关联securityManager
        bean.setSecurityManager(securityManager);

        // 采用 LinkedHashMap 为了让存储的键值对有顺序
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 认证过滤器
        // 登录验证的请求不能拦截
        filterChainDefinitionMap.put("/user/login", "anon");
        // druid数据源监控也不拦截
        filterChainDefinitionMap.put("/druid/**", "anon");
        // 验证码请求
        filterChainDefinitionMap.put("/defaultKaptcha", "anon");

        // 添加授权过滤器
        filterChainDefinitionMap.put("/product/toAdd", "perms[product:add]");
        filterChainDefinitionMap.put("/product/toUpdate", "perms[product:update]");
        filterChainDefinitionMap.put("/product/toList", "perms[product:list]");

        // 添加user过滤器
        // /index 请求只要使用了 rememberMe 功能，就可以访问
        // filterChainDefinitionMap.put("/index", "user");
        filterChainDefinitionMap.put("/index", "userFormAuthenticationFilter");

        // 拦截所有请求
        // ----这个一定要放在最后----
         filterChainDefinitionMap.put("/**", "authc");

        // 把自定义的Filter添加到shiro过滤器列表
        Map<String, Filter> filters = new LinkedHashMap<>();
        filters.put("userFormAuthenticationFilter", userFormAuthenticationFilter());
        bean.setFilters(filters);

        // 添加shiro过滤器
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        // 修改登录请求
        bean.setLoginUrl("/toLogin");
        // 设置未授权页面
        bean.setUnauthorizedUrl("/unauth");

        return bean;
    }

    /**
     * 7. 自定义认证过滤器
     *      修改 RememberMe 的功能的bug
     *          在通过 RememberMe 登录之后，用户信息丢失的漏洞
     * @return
     */
    @Bean(name = "userFormAuthenticationFilter")
    public UserFormAuthenticationFilter userFormAuthenticationFilter() {
        return new UserFormAuthenticationFilter();
    }

    /**
     * 2. 创建 securityManager
     *
     * @return
     */
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(MyRealm myRealm,
                                           CookieRememberMeManager cookieRememberMeManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 关联 MyRealm
        securityManager.setRealm(myRealm);

        // 关联remember me的manager
        securityManager.setRememberMeManager(cookieRememberMeManager);

        return securityManager;
    }

    /**
     * 6. 创建rememberMe的 cookieManager
     *
     * @return
     */
    @Bean
    public CookieRememberMeManager cookieRememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        // 关联cookie
        cookieRememberMeManager.setCookie(simpleCookie());

        return cookieRememberMeManager;
    }

    /**
     * 5. RememberMe的功能
     *
     *      创建 cookie
     * @return
     */
    @Bean
    public SimpleCookie simpleCookie() {
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        // 设置 cookie 的时间长度，以秒为单位
        simpleCookie.setMaxAge(2592000);
        // 设置只读模型
        simpleCookie.setHttpOnly(true);

        return simpleCookie;
    }

    /**
     * 3. 自定义 realm
     *
     * @return
     */
    @Bean
    public MyRealm myRealm() {
        MyRealm myRealm = new MyRealm();

        return myRealm;
    }

    /**
     * 4. thymeleaf整合shiro标签
     *
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }

}
